/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.workflow.service.usertask;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Strings;
import com.je.bpm.engine.ActivitiException;
import com.je.bpm.engine.ProcessEngine;
import com.je.bpm.engine.TaskService;
import com.je.bpm.engine.delegate.DelegateExecution;
import com.je.bpm.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import com.je.bpm.engine.impl.identity.Authentication;
import com.je.bpm.engine.impl.persistence.entity.PassRoundEntity;
import com.je.bpm.engine.impl.persistence.entity.VariableInstance;
import com.je.bpm.engine.runtime.Execution;
import com.je.bpm.model.process.model.ProcessDismissNodeInfo;
import com.je.bpm.model.process.model.ProcessGobackNodeInfo;
import com.je.bpm.model.process.model.ProcessNextNodeInfo;
import com.je.bpm.model.process.results.*;
import com.je.bpm.runtime.process.ProcessOperatorService;
import com.je.bpm.runtime.shared.RemoteCallServeManager;
import com.je.bpm.runtime.shared.operator.validator.PayloadValidErrorException;
import com.je.common.base.DynaBean;
import com.je.common.base.service.MetaService;
import com.je.common.base.util.DateUtils;
import com.je.common.base.util.SecurityUserHolder;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.ibatis.extension.plugins.pagination.Page;
import com.je.workflow.service.user.WorkFlowUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ProcessInfoServiceImpl implements ProcessInfoService {
    @Autowired
    MetaService metaService;
    @Autowired
    ProcessOperatorService processOperatorService;
    @Autowired
    TaskService taskService;
    @Autowired
    RemoteCallServeManager remoteCallServeManager;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private WorkFlowUserService workFlowUserService;

    @Override
    public List<ProcessNextNodeInfo> getSubmitOutGoingNode(String taskId, String pdid, String prod, String beanId, String tableCode) {
        ProcessNextElementResult processNextElementResult = null;
        try {
            processNextElementResult = processOperatorService.getSubmitOutGoingNode(taskId, pdid, prod, getBean(prod, beanId, tableCode));
        } catch (PayloadValidErrorException e) {
            e.printStackTrace();
        }
        List<ProcessNextNodeInfo> list = processNextElementResult.getEntity();
        return list;
    }

    private Map<String, Object> getBean(String prod, String beanId, String tableCode) {
        Object dynaBeanObject = remoteCallServeManager.doGet(prod, beanId, tableCode, null);
        if (dynaBeanObject == null) {
            throw new ActivitiException("获取bean信息异常！");
        }
        Map<String, Object> map = (Map<String, Object>) dynaBeanObject;
        return (Map<String, Object>) map.get("values");
    }

    //    @Override
//    public ProcessNextElementAssigneeResult getSubmitOutGoingNodeAssignee(String taskId, String pdid, String prod, String beanId,
//                                                                          String target, String tableCode, String operationId) {
//        Map<String, Object> bean = getBean(prod, beanId, tableCode);
//        ProcessNextElementAssigneeResult processNextElementResult = null;
//        try {
//            processNextElementResult = processOperatorService.getSubmitOutGoingNodeAssignee(taskId, pdid, prod, target, bean, operationId);
//        } catch (PayloadValidErrorException e) {
//            e.printStackTrace();
//        }
//        return processNextElementResult;
//    }
    @Override
    public JSONObject getSubmitOutGoingNodeAssignee(String taskId, String pdid, String prod, String beanId,
                                                    String target, String tableCode, String operationId) {
        Map<String, Object> bean = getBean(prod, beanId, tableCode);
        ProcessNextElementAssigneeResult processNextElementResult = null;
        try {
            processNextElementResult = processOperatorService.getSubmitOutGoingNodeAssignee(taskId, pdid, prod, target, bean, operationId);
        } catch (PayloadValidErrorException e) {
            e.printStackTrace();
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("nodeAssigneeInfo", processNextElementResult.getEntity().getUser());
        jsonObject.put("commonUserInfo", commonUserInfo());
        return jsonObject;
    }

    @Override
    public ProcessGobackNodeInfo getGobackNode(String piid, String taskId) {
        ProcessGobackElementResult result = null;
        try {
            result = processOperatorService.getGobackNodeName(piid, taskId);
        } catch (PayloadValidErrorException e) {
            e.printStackTrace();
        }
        ProcessGobackNodeInfo processGobackNodeInfo = result.getEntity();
        return processGobackNodeInfo;
    }

    @Override
    public ProcessGobackNodeInfo getRetrieveNode(String piid, String taskId) {
        ProcessGobackElementResult result = null;
        try {
            result = processOperatorService.getRetrieveNodeName(piid, taskId);
        } catch (PayloadValidErrorException e) {
            e.printStackTrace();
        }
        ProcessGobackNodeInfo processGobackNodeInfo = result.getEntity();
        return processGobackNodeInfo;
    }

    @Override
    public ProcessNextNodeInfo getDelegationNode(String piid, String taskId) {
        ProcessDelegateElementResult result = null;
        try {
            result = processOperatorService.getDelegateNode(piid, taskId);
        } catch (PayloadValidErrorException e) {
            e.printStackTrace();
        }
        ProcessNextNodeInfo processNextNodeInfo = result.getEntity();
        return processNextNodeInfo;
    }

    @Override
    public List<ProcessDismissNodeInfo> getDismissOutGoingNode(String piid, String taskId, String pdid) {
        ProcessDismissElementResult processDismissElementResult = null;
        try {
            processDismissElementResult = processOperatorService.getDismissOutGoingNode(piid, taskId, pdid, null);
        } catch (PayloadValidErrorException e) {
            e.printStackTrace();
        }
        List<ProcessDismissNodeInfo> list = processDismissElementResult.getEntity();
        return list;
    }

    @Override
    public ProcessGobackNodeInfo getDirectDeliveryNode(String piid, String taskId) {
        ProcessGobackElementResult result = null;
        try {
            result = processOperatorService.getDismissNodeName(piid, taskId);
        } catch (PayloadValidErrorException e) {
            e.printStackTrace();
        }
        ProcessGobackNodeInfo processGobackNodeInfo = result.getEntity();
        return processGobackNodeInfo;
    }

    @Override
    public ProcessCirculatedElementResult getPassRoundUsers(String taskId, String prod, String beanId, String tableCode) throws PayloadValidErrorException {
        Map<String, Object> dynaBean = getBean(prod, beanId, tableCode);
        return processOperatorService.getCirculatedInfo(taskId, prod, dynaBean);
    }

    @Override
    public Map<String, Object> getCounterSignerOperationalUsers(String taskId) {
        Map<String, Object> result = taskService.getCounterSignerOperationalUsers(taskId);
        if (result == null) {
            return null;
        }
        if (result.get("usersInfo") != null && result.get("usersInfo") instanceof List) {
            List<Map<String, String>> list = (List<Map<String, String>>) result.get("usersInfo");
            //如果负责人信息不为空
            if (result.get("oneBallotUserId") != null) {
                String oneBallotUserId = (String) result.get("oneBallotUserId");
                List<Map<String, String>> userList = null;
                for (Map<String, String> user : list) {
                    if (user.get("userId") != null && user.get("userId").equals(oneBallotUserId)) {
                        userList = new ArrayList<>();
                        userList.add(user);
                    }
                }
                if (userList != null && userList.size() > 0) {
                    list.removeAll(userList);
                }
            }
            for (Map<String, String> user : list) {
                String userId = user.get("userId");
                String deptName = workFlowUserService.getUserDeptNameById(userId);
                user.put("userAvatar", workFlowUserService.getUserPhotoById(userId));
                if (Strings.isNullOrEmpty(deptName)) {
                    user.put("userName", workFlowUserService.getUserNameById(userId));
                } else {
                    user.put("userName", workFlowUserService.getUserNameById(userId) + String.format("(%s)", deptName));
                }
            }
        }

        if (result.get("oneBallotUserId") != null) {
            String oneBallotUserId = (String) result.get("oneBallotUserId");
            String oneBallotUserName = workFlowUserService.getUserNameById(oneBallotUserId);
            result.put("oneBallotUserName", oneBallotUserName);
        }

        return result;
    }

    @Override
    public String getCountersignApprovalOpinion(String taskId) {
        String executionIdByTaskId = taskService.getRootExecutionIdByTaskId(taskId);
        List<Execution> miExecutions = processEngine.getRuntimeService().createExecutionQuery().executionId(executionIdByTaskId).list();
        if (miExecutions.size() == 0) {
            return "";
        }
        JSONObject processingInfo = getJsonObject((DelegateExecution) miExecutions.get(0), MultiInstanceActivityBehavior.PROCESSING_INFO);
        if (processingInfo != null) {
            JSONObject opinions = (JSONObject) processingInfo.get("opinions");
            Object opinion = opinions.get(Authentication.getAuthenticatedUser().getDeptId());
            String oldOpinion = (String) opinion;
            return oldOpinion;
        }
        return "";
    }

    @Override
    public List<Map<String, String>> getPassRoundUsersListByTaskId(String taskId,String userId) {
        List<Map<String, String>> resultMap = new ArrayList<>();
        List<PassRoundEntity> list = processEngine.getProcessEngineConfiguration().getHistoryService().getPassRoundByTaskId(taskId, userId);
        for (PassRoundEntity passRoundEntity : list) {
            Map<String, String> map = new HashMap<>();
            map.put("handler", passRoundEntity.getTo());
            map.put("handlerName", workFlowUserService.getUserNameById(passRoundEntity.getTo()));
            if (passRoundEntity.getReadStateString() != null) {
                map.put("operation", "已审阅");
            } else {
                map.put("operation", "未处理");
            }
            map.put("comment", passRoundEntity.getContent());
            map.put("approvalTime", DateUtils.formatDateTime(passRoundEntity.getReadTime()));
            resultMap.add(map);
        }
        return resultMap;
    }

    @Override
    public List<Map<String, Object>> getAssigneeByTaskId(String taskId, String currentNodeId) {
        List<Map<String, Object>> result = new ArrayList<>();
        List<String> list = processEngine.getProcessEngineConfiguration().getRuntimeService()
                .getAssigneeByTaskIdAndCurrentNodeId(taskId, currentNodeId);
        for (String userId : list) {
            result.add(workFlowUserService.getUserInfoByUserId(userId));
        }
        return result;
    }

    protected JSONObject getJsonObject(DelegateExecution execution, String variableName) {
        Map<String, VariableInstance> map = processEngine.getProcessEngineConfiguration().getRuntimeService().getVariableInstances(execution.getId());
        VariableInstance value = map.get(variableName);
        String textValue = value.getTextValue();
        if (!Strings.isNullOrEmpty(textValue)) {
            return JSONObject.parseObject(textValue);
        } else {
            return null;
        }
    }

    /**
     * 获取我催办的数据
     *
     * @param taskId
     * @param piid
     * @param currentNodeId
     * @return
     */
    @Override
    public Page getUrgeData(Page page, String taskId, String piid, String currentNodeId, String type) {
        //分页对象
        ConditionsWrapper conditionsWrapper = ConditionsWrapper.builder();
        conditionsWrapper.table("act_log_urge");
        conditionsWrapper.eq("PROCESS_INSTANCE_ID_", piid).eq("TASK_ID_", taskId)
                .eq(type, Authentication.getAuthenticatedUser().getDeptId())
                .orderByDesc("CREATE_TIME_");
        List<Map<String, Object>> list = metaService.load("", page, conditionsWrapper);
        page.setRecords(list);
        return page;
    }

    @Override
    public JSONArray commonUserInfo() {
        JSONArray jsonArray = new JSONArray();
        //当前登陆人的用户、部门id
        String loginUserId = SecurityUserHolder.getCurrentAccountRealUserId();
        String realOrgId = SecurityUserHolder.getCurrentAccountDepartment().getId();
        // 获取常用人中所有的id
        String whereSql = " AND SY_CREATEUSERID = '" + loginUserId + "' AND SY_CREATEORGID = '" + realOrgId + "' ORDER BY COMMONUSER_COUNT DESC,SY_CREATETIME DESC";
        List<DynaBean> dynaBeanList = metaService.select("JE_WORKFLOW_COMMONUSER", ConditionsWrapper.builder().apply(whereSql));
        JSONObject json = null;
        if (null != dynaBeanList && !dynaBeanList.isEmpty()) {
            List<DynaBean> newDynaBeanList = dynaBeanList.size() > 10 ? dynaBeanList.subList(0, 10) : dynaBeanList;
            for (int i = 0; i < newDynaBeanList.size(); i++) {
                json = new JSONObject();
                json.put("userId", newDynaBeanList.get(i).getStr("COMMONUSER_USER_ID"));
                json.put("userName", newDynaBeanList.get(i).getStr("COMMONUSER_USER_NAME"));
                jsonArray.add(json);
            }
        }
        return jsonArray;
    }

}

